package com.qtong.controller.assignment;

import com.qtong.entity.Result;
import com.qtong.entity.cinemas.Cinemas;
import com.qtong.entity.movies.Movie;
import com.qtong.entity.screenings.Screening;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Test data creation endpoints. Accepts user-provided payloads so you can generate test data locally.
 */
@RestController
@RequestMapping("/assignment/sample")
public class TestDataController {

    @Autowired
    private MongoTemplate mongoTemplate;

    public static class SamplePayload {
        public List<Map<String, Object>> cinemas;
        public List<Map<String, Object>> movies;
        public List<Map<String, Object>> screenings;
    }

    /**
     * Upsert user-provided sample data. Payload is flexible maps so you can control fields locally.
     * Example payload:
     * {
     *  "cinemas": [{"cinemaId":"JN001","name":"济南新时代","address":"...","region": {"city":"济南"}, "location": {"type":"Point","coordinates":[117.1,36.6]}}],
     *  "movies": [{"movieId":"M2024001","title":"示例片","director":"张艺谋","actors":["王宝强"]}],
     *  "screenings": [{"screeningId":"S20240615001","movieId":"M2024001","cinemaId":"JN001","hallId":"JN001-H01","showTime":"2025-11-07T10:00:00Z","ticketPrice":59.9}]
     * }
     */
    @PostMapping("/create")
    public Result createSample(@RequestBody SamplePayload payload) {
        int cinemasInserted = 0, moviesInserted = 0, screeningsInserted = 0, cinemasUpdated = 0, moviesUpdated = 0, screeningsUpdated = 0;

        if (payload == null) return Result.error("payload missing");

        // cinemas
        if (payload.cinemas != null) {
            for (Map<String, Object> m : payload.cinemas) {
                Object cid = m.get("cinemaId");
                if (cid == null) continue;
                String cinemaId = cid.toString();
                Query q = new Query(Criteria.where("cinemaId").is(cinemaId));
                Cinemas existing = mongoTemplate.findOne(q, Cinemas.class);
                if (existing == null) {
                    Cinemas c = new Cinemas();
                    c.setCinemaId(cinemaId);
                    c.setName((String) m.getOrDefault("name", m.getOrDefault("cinemaName", "")));
                    c.setAddress((String) m.getOrDefault("address", ""));
                    c.setContact((String) m.getOrDefault("contact", m.getOrDefault("phone", null)));
                    Object region = m.get("region");
                    if (region instanceof Map) {
                        Map<String,Object> rmap = (Map<String,Object>) region;
                        com.qtong.entity.cinemas.Region reg = new com.qtong.entity.cinemas.Region();
                        reg.setProvince((String) rmap.getOrDefault("province", null));
                        reg.setCity((String) rmap.getOrDefault("city", null));
                        c.setRegion(reg);
                    }
                    Object loc = m.get("location");
                    if (loc instanceof Map) c.setLocation((Map<String,Object>) loc);
                    mongoTemplate.save(c);
                    cinemasInserted++;
                } else {
                    // update simple fields
                    boolean changed = false;
                    if (m.containsKey("name")) { existing.setName((String) m.get("name")); changed = true; }
                    if (m.containsKey("address")) { existing.setAddress((String) m.get("address")); changed = true; }
                    if (m.containsKey("contact")) { existing.setContact((String) m.get("contact")); changed = true; }
                    if (m.containsKey("location")) { existing.setLocation((Map<String,Object>) m.get("location")); changed = true; }
                    if (changed) { mongoTemplate.save(existing); cinemasUpdated++; }
                }
            }
        }

        // movies
        if (payload.movies != null) {
            for (Map<String, Object> m : payload.movies) {
                Object mid = m.get("movieId");
                if (mid == null) continue;
                String movieId = mid.toString();
                Query q = new Query(Criteria.where("movieId").is(movieId));
                Movie existing = mongoTemplate.findOne(q, Movie.class);
                if (existing == null) {
                    Movie mv = new Movie();
                    mv.setMovieId(movieId);
                    mv.setTitle((String) m.getOrDefault("title", ""));
                    mv.setDirector((String) m.getOrDefault("director", null));
                    Object actors = m.get("actors");
                    if (actors instanceof List) mv.setActors((List<String>) actors);
                    mv.setDuration(m.get("duration") instanceof Number ? ((Number)m.get("duration")).intValue() : null);
                    mv.setPosterUrl((String) m.getOrDefault("posterUrl", null));
                    mongoTemplate.save(mv);
                    moviesInserted++;
                } else {
                    boolean changed = false;
                    if (m.containsKey("title")) { existing.setTitle((String) m.get("title")); changed = true; }
                    if (m.containsKey("director")) { existing.setDirector((String) m.get("director")); changed = true; }
                    if (m.containsKey("actors") && m.get("actors") instanceof List) { existing.setActors((List<String>) m.get("actors")); changed = true; }
                    if (changed) { mongoTemplate.save(existing); moviesUpdated++; }
                }
            }
        }

        // screenings
        if (payload.screenings != null) {
            for (Map<String, Object> m : payload.screenings) {
                Object sid = m.get("screeningId");
                if (sid == null) continue;
                String screeningId = sid.toString();
                Query q = new Query(Criteria.where("screeningId").is(screeningId));
                Screening existing = mongoTemplate.findOne(q, Screening.class);
                if (existing == null) {
                    Screening s = new Screening();
                    s.setScreeningId(screeningId);
                    s.setMovieId((String) m.getOrDefault("movieId", null));
                    s.setCinemaId((String) m.getOrDefault("cinemaId", null));
                    s.setHallId((String) m.getOrDefault("hallId", null));
                    Object st = m.get("showTime");
                    if (st instanceof String) {
                        try { s.setShowTime(java.util.Date.from(java.time.Instant.parse((String) st))); } catch (Exception e) { /* ignore */ }
                    }
                    if (m.containsKey("ticketPrice") && m.get("ticketPrice") instanceof Number) s.setTicketPrice(((Number)m.get("ticketPrice")).doubleValue());
                    // seatLayout optional
                    if (m.containsKey("seatLayout") && m.get("seatLayout") instanceof Map) {
                        Map<String,Object> sl = (Map<String,Object>) m.get("seatLayout");
                        Screening.SeatLayout layout = new Screening.SeatLayout();
                        if (sl.get("rows") instanceof Number) layout.setRows(((Number)sl.get("rows")).intValue());
                        if (sl.get("cols") instanceof Number) layout.setCols(((Number)sl.get("cols")).intValue());
                        s.setSeatLayout(layout);
                    }
                    mongoTemplate.save(s);
                    screeningsInserted++;
                } else {
                    boolean changed = false;
                    if (m.containsKey("ticketPrice") && m.get("ticketPrice") instanceof Number) { existing.setTicketPrice(((Number)m.get("ticketPrice")).doubleValue()); changed = true; }
                    if (m.containsKey("showTime") && m.get("showTime") instanceof String) { try { existing.setShowTime(java.util.Date.from(java.time.Instant.parse((String)m.get("showTime")))); changed = true; } catch (Exception e) {} }
                    if (changed) { mongoTemplate.save(existing); screeningsUpdated++; }
                }
            }
        }

        String msg = String.format("cinemas: +%d updates:%d, movies: +%d updates:%d, screenings: +%d updates:%d",
                cinemasInserted, cinemasUpdated, moviesInserted, moviesUpdated, screeningsInserted, screeningsUpdated);

        return Result.success(msg);
    }

    /**
     * Remove by ids. Provide arrays of ids to delete (optional fields). Empty payload does nothing.
     */
    public static class ClearPayload {
        public List<String> cinemaIds;
        public List<String> movieIds;
        public List<String> screeningIds;
    }

    @PostMapping("/clear")
    public Result clearByIds(@RequestBody ClearPayload payload) {
        if (payload == null) return Result.error("payload missing");
        int c=0,m=0,s=0;
        if (payload.cinemaIds != null) {
            for (String id : payload.cinemaIds) {
                mongoTemplate.remove(new Query(Criteria.where("cinemaId").is(id)), Cinemas.class); c++;
            }
        }
        if (payload.movieIds != null) {
            for (String id : payload.movieIds) {
                mongoTemplate.remove(new Query(Criteria.where("movieId").is(id)), Movie.class); m++;
            }
        }
        if (payload.screeningIds != null) {
            for (String id : payload.screeningIds) {
                mongoTemplate.remove(new Query(Criteria.where("screeningId").is(id)), Screening.class); s++;
            }
        }
        return Result.success(String.format("removed cinemas:%d movies:%d screenings:%d", c,m,s));
    }
}
